import {
  ButtonGroup,
  ButtonGroupItem,
  Dialog,
  DialogType,
  IconText,
  InputField,
  InputType,
  Size
} from 'nightwatch-ui';
import React, { useEffect, useState } from 'react';
import { isMobile } from 'react-device-detect';
import styled from 'styled-components';

import { decryptSecretWithWallet, getInjectedAddr } from '../../../utils/walletUtils';
import { isEthereumEnabled } from '../../../utils/walletUtils/isWalletEnabled';

const MFA_TOKEN_LENGTH = 6;
interface ConfirmPasswordModalBaseProps {
  onClose: () => void;
  open: boolean;
  onSubmit: (password: string, tokenMFA: string) => Promise<void>;
  description?: string;
  errorMsg: string;
  setErrorMsg: (errorMsg: string) => void;
  showTokenMFA: boolean;
  setShowTokenMFA: (showTokenMFA: boolean) => void;
  encryptedMetamaskSecret: string | undefined;
}

const ButtonContainer = styled.div`
  margin-top: 12px;
  width: 100%;
`;

function ConfirmPasswordModalBase(props: ConfirmPasswordModalBaseProps) {
  const {
    errorMsg,
    onClose,
    open,
    onSubmit,
    setErrorMsg,
    showTokenMFA,
    setShowTokenMFA,
    description,
    encryptedMetamaskSecret
  } = props;
  const [password, setPassword] = useState('');
  const [tokenMFA, setTokenMFA] = useState('');
  const [isSubmitting, setIsSubmitting] = useState(false);
  const [showBackupCode, setShowBackupCode] = useState(false);

  // If the user is using a legacy metamask account when we autogenerated their password,
  // we autofill the old password, which may not be known to them on the initial login.
  useEffect(() => {
    const setOldPwFromSecret = async () => {
      if (isEthereumEnabled() && encryptedMetamaskSecret) {
        const ethAddr = await getInjectedAddr();
        if (!ethAddr) return;
        const decryptedSecret = await decryptSecretWithWallet(ethAddr, encryptedMetamaskSecret);
        if (!decryptedSecret) {
          console.error('Could not decrypt existing secret');
          return;
        }
        setPassword(decryptedSecret);
      }
    };
    if (!tokenMFA) {
      void setOldPwFromSecret();
    }
  }, [encryptedMetamaskSecret]);

  const runSubmit = async () => {
    setIsSubmitting(true);
    await onSubmit(password, tokenMFA);
    setIsSubmitting(false);
  };

  const handleInputKeyPress = (e: React.KeyboardEvent) => {
    if (e.key === 'Enter') void runSubmit();
  };

  const confirmPasswordField = (
    <>
      <InputField
        autoComplete='current-password' // https://www.chromium.org/developers/design-documents/form-styles-that-chromium-understands/
        autoFocus
        error={errorMsg}
        onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
          if (errorMsg !== '') setErrorMsg('');
          setPassword(e.target.value);
        }}
        onKeyPress={handleInputKeyPress}
        placeholder='Enter your password'
        type={InputType.PASSWORD}
        value={password}
      />
    </>
  );

  // Returns either a TOTP 6-digit input field or a regular input field
  const tokenMFAField = !showBackupCode ? (
    <InputField
      autoFocus
      error={errorMsg}
      onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
        if (errorMsg !== '') setErrorMsg('');
        setTokenMFA(e.target.value);
      }}
      onKeyPress={(e: React.KeyboardEvent) => {
        if (e.key === 'Enter') {
          void runSubmit();
        }
      }}
      placeholder={`Enter ${MFA_TOKEN_LENGTH}-digit code`}
      value={tokenMFA}
    />
  ) : (
    <InputField
      autoFocus
      error={errorMsg}
      onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
        if (errorMsg !== '') setErrorMsg('');
        setTokenMFA(e.target.value);
      }}
      onKeyPress={(e: React.KeyboardEvent) => {
        if (e.key === 'Enter') {
          void runSubmit();
        }
      }}
      placeholder='Enter 10-character backup code'
      value={tokenMFA}
    />
  );

  const closeAndResetFields = () => {
    onClose();
    // Reset all fields
    setPassword('');
    setTokenMFA('');
    setShowTokenMFA(false);
  };

  return (
    <Dialog
      customContent
      description={description || 'We confirm your identity when performing sensitive actions.'}
      inputField={showTokenMFA ? tokenMFAField : confirmPasswordField}
      onClose={closeAndResetFields}
      open={open}
      title='Authentication required'
      type={DialogType.CONFIRM}
    >
      {showTokenMFA && (
        <IconText
          label={showBackupCode ? 'Go back' : 'Have a backup code?'}
          onClick={() => {
            setTokenMFA('');
            setErrorMsg('');
            setShowBackupCode(!showBackupCode);
          }}
          size={Size.SMALL}
          wrap={isMobile}
        />
      )}
      <ButtonContainer>
        <ButtonGroup fullWidth={true}>
          <ButtonGroupItem label='Confirm' onClick={() => void runSubmit()} />
          <ButtonGroupItem label='Cancel' onClick={closeAndResetFields} />
        </ButtonGroup>
      </ButtonContainer>
    </Dialog>
  );
}

export default ConfirmPasswordModalBase;
